﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Core.Model;
using System.Data.Objects;
using System.Data.EntityClient;
using Core.UnitOfWork;
using Core.Repository;
using System.Transactions;
using System.Data.Entity;

namespace Core.Service
{
    public class NodeService<TEntity, TContext> : Service<TEntity,TContext>, INodeService<TEntity>
        where TEntity : class,INode<TEntity>
        where TContext : DbContext, new()
    {
        public override void Add(TEntity item)
        {
            using (TContext context = new TContext())
            {
                using (TransactionScope transaction = new TransactionScope())
                {
                    IUnitOfWork unitOfWork = new UnitOfWork.UnitOfWork(context);
                    INodeRepository<TEntity> repository = new NodeRepository<TEntity>(unitOfWork);

                    TEntity parent = null;
                    if (item.ParentId == null)
                    {
                        //item.ParentId = 0;
                    }
                    else
                    {
                        parent = repository.Get(item.ParentId);
                    }

                    item.Leaf = true;
                    repository.Add(item);
                    unitOfWork.Save();
                    
                    if (parent != null)
                    {
                        item.Level = parent.Level + 1;
                        item.Path = string.Format("{0}.{1}", parent.Path, item.Id.ToString());

                        parent.Leaf = false;
                        repository.Update(parent);
                    }
                    else
                    {
                        item.Level = 1;
                        item.Path = item.Id.ToString() ;
                    }
                    repository.Update(item);
                    unitOfWork.Save();

                    transaction.Complete();
                }
            }
        }

        public override void Update(TEntity item)
        {
            using (TContext context = new TContext())
            {
                using (TransactionScope transaction = new TransactionScope())
                {
                    IUnitOfWork unitOfWork = new UnitOfWork.UnitOfWork(context);
                    INodeRepository<TEntity> repository = new NodeRepository<TEntity>(unitOfWork);

                    TEntity entityInDb = repository.Get(item.Id);
                    
                    if(entityInDb.ParentId != item.ParentId)
                        throw new Exception(string.Format("不能更改父节点！", item.Id));

                    repository.Update(item);
                    unitOfWork.Save();

                    transaction.Complete();
                }
            }
        }

        public override void Delete(TEntity item)
        {
            using (TContext context = new TContext())
            {
                using (TransactionScope transaction = new TransactionScope())
                {
                    IUnitOfWork unitOfWork = new UnitOfWork.UnitOfWork(context);
                    INodeRepository<TEntity> repository = new NodeRepository<TEntity>(unitOfWork);

                    TEntity parent = null;
                    if (item.ParentId != null)
                    {
                        parent = repository.Get(item.ParentId);
                    }

                    foreach (var i in repository.Find(c => c.Path.Contains(item.Path)))
                    {
                        repository.Delete(i);
                    }
                    unitOfWork.Save();

                    if (parent != null)
                    {
                        if (parent.Children == null) 
                        {
                            parent.Leaf = true;
                        }
                        else if (parent.Children.Count == 0)
                        {
                            parent.Leaf = true;
                        }
                        repository.Update(parent);
                        unitOfWork.Save();
                    }
                    transaction.Complete();
                }
            }
        }



        public TEntity GetParent(int parentId)
        {
            using (TContext context = new TContext())
            {
                IUnitOfWork unitOfWork = new UnitOfWork.UnitOfWork(context);
                INodeRepository<TEntity> repository = new NodeRepository<TEntity>(unitOfWork);
                return repository.GetParent(parentId);
            }
        }

        public IList<TEntity> GetChildren(int parentId)
        {
            using (TContext context = new TContext())
            {
                IUnitOfWork unitOfWork = new UnitOfWork.UnitOfWork(context);
                INodeRepository<TEntity> repository = new NodeRepository<TEntity>(unitOfWork);
                return repository.GetChildren(parentId);
            }
        }
    }
}
